// This source is subject to the Microsoft Public License.
// See http://www.microsoft.com/resources/sharedsource/licensingbasics/sharedsourcelicenses.mspx.
// All other rights reserved.

using System;
using System.Collections;
using System.ComponentModel;
using System.Configuration;
using System.Data;
using System.Drawing;
using System.Globalization;
using System.Resources;
using System.Threading;
using System.Web;
using System.Web.SessionState;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using System.Xml;

using Infragistics.WebUI.UltraWebNavigator;

namespace QuoteAdvantage
{
   /// <summary>
   /// Main window for QuoteAdvantage
   /// </summary>
   public partial class CustomizeQuote2 : System.Web.UI.Page
   {
      protected Quote objQuote = null;
      protected string m_strQuoteId = "";
      protected string strCategoryId = "";
      protected Engine eng = null;
      protected Organization objOrganization = null;
      protected ResourceManager m_mgrResource;
      protected int nCurrencyFormatCode;
      protected string strCurrencySymbol;
      protected string strParentProductCustomHeader1 = "";
      protected string strParentProductCustomHeader2 = "";
      protected System.Drawing.Color objCustomizeLinkColor = Color.Blue;
      protected XmlNode nodeCategoryList = null;


      protected void Page_Load(object sender, System.EventArgs e)
      {
         if (this.Trace.IsEnabled)
         {
            this.Trace.Write("Starting Page Load event.");
            this.Trace.Write("QueryString: " + Request.QueryString.ToString());
            this.Trace.Write("Form Variables: " + Request.Form.Count);
         }

         m_strQuoteId = Request.QueryString["id"];  // CRM 4.0

         if (m_strQuoteId == null)
         {
            m_strQuoteId = Request.QueryString["oId"];  // CRM 3.0
         }

         // TESTING
         if (m_strQuoteId == null)
         {
            m_strQuoteId = ConfigurationManager.AppSettings["TestQuoteId"];
         }

         if (this.Trace.IsEnabled)
         {
            this.Trace.Write("QuoteId=" + m_strQuoteId);
         }

         if (Request.QueryString["CategoryId"] != null)
         {
            strCategoryId = Request.QueryString["CategoryId"];
         }

         // Set the culture and UI culture to the browser's accept language
         Thread.CurrentThread.CurrentCulture = CultureInfo.CreateSpecificCulture(Request.UserLanguages[0]);
         Thread.CurrentThread.CurrentUICulture = new CultureInfo(Request.UserLanguages[0]);

         m_mgrResource = new ResourceManager("QuoteAdvantage.strings", typeof(CustomizeQuote).Assembly);

         if (this.Trace.IsEnabled)
            this.Trace.Write("Initializing Engine");
         eng = new Engine(this.Trace, m_mgrResource);

         objQuote = eng.LoadQuote(new Guid(m_strQuoteId));
         objOrganization = eng.LoadOrganization();
         strCurrencySymbol = objOrganization.CurrencySymbol;
         nCurrencyFormatCode = objOrganization.CurrencyFormatCode;

         // Load link color for the customize links in the quote items grid
         if (ConfigurationManager.AppSettings["CustomizeLinkColor"] != null)
         {
            if (ConfigurationManager.AppSettings["CustomizeLinkColor"] != "")
            {
               objCustomizeLinkColor = Color.FromName(ConfigurationManager.AppSettings["CustomizeLinkColor"]);
            }
         }

         LoadCategoryList();

         if (!this.IsPostBack)
         {
            if (this.Trace.IsEnabled)
               this.Trace.Write("Initializing Page...");

            LoadResources();
            LoadProductCategoryList(ctlTree);
            LoadProductCategoryList2(ctlTree2);
            SelectCategory(strCategoryId);
            RefreshAvailableProducts();
            RefreshQuoteItems();

            btnPrint.Attributes.Add("onclick", "return onPrintClicked()");
            if (this.Trace.IsEnabled)
               this.Trace.Write("Page Complete.");
         }
      }

      #region Web Form Designer generated code
      override protected void OnInit(EventArgs e)
      {
         //
         // CODEGEN: This call is required by the ASP.NET Web Form Designer.
         //
         InitializeComponent();
         base.OnInit(e);
      }

      /// <summary>
      /// Required method for Designer support - do not modify
      /// the contents of this method with the code editor.
      /// </summary>
      private void InitializeComponent()
      {
         this.ctlTree.NodeClicked += new Infragistics.WebUI.UltraWebNavigator.NodeClickedEventHandler(this.ctlTree_NodeClicked);
         this.btnDiscount.Click += new System.Web.UI.ImageClickEventHandler(this.btnDiscount_Click);
      }
      #endregion

      private void LoadResources()
      {
         lblProductCategories.Text = m_mgrResource.GetString("lblProductCategories");
         lblAvailableItemsInCategory.Text = m_mgrResource.GetString("lblAvailableItemsInCategory");
         lblCustomizableProducts.Text = m_mgrResource.GetString("lblCustomizableProducts");

         gridAvailableProducts3.Columns[1].HeaderText = m_mgrResource.GetString("hdrName");
         gridAvailableProducts3.Columns[2].HeaderText = m_mgrResource.GetString("hdrProductId");
         gridAvailableProducts3.Columns[3].HeaderText = m_mgrResource.GetString("hdrStandardCost");
         gridAvailableProducts3.Columns[4].HeaderText = m_mgrResource.GetString("hdrListPrice");
         gridAvailableProducts3.Columns[5].HeaderText = m_mgrResource.GetString("hdrPrice");

         gridQuoteItems3.Columns[0].HeaderText = m_mgrResource.GetString("hdrName");
         gridQuoteItems3.Columns[2].HeaderText = m_mgrResource.GetString("hdrBasePrice");
         gridQuoteItems3.Columns[3].HeaderText = m_mgrResource.GetString("hdrQty");
         gridQuoteItems3.Columns[4].HeaderText = m_mgrResource.GetString("hdrMultiplier");
         gridQuoteItems3.Columns[8].HeaderText = m_mgrResource.GetString("hdrCustomizedPrice");

         // Hide/Show optional columns in the available product list
         gridAvailableProducts3.Columns[3].Visible = false;
         gridAvailableProducts3.Columns[4].Visible = false;

         if (ConfigurationManager.AppSettings["ShowStandardCostColumn"] != null)
         {
            bool bVisible = Convert.ToBoolean(ConfigurationManager.AppSettings["ShowStandardCostColumn"]);
            gridAvailableProducts3.Columns[3].Visible = bVisible;
         }

         if (ConfigurationManager.AppSettings["ShowListPriceColumn"] != null)
         {
            bool bVisible = Convert.ToBoolean(ConfigurationManager.AppSettings["ShowListPriceColumn"]);
            gridAvailableProducts3.Columns[4].Visible = bVisible;
         }

         // Load the names of any custom fields that need to be included
         // Quote Item columns are:
         //    0: Name
         //    1: Custom 1
         //    2: Base Price
         //    3: Qty
         //    4: Multiplier
         //    5: Discount %
         //    6: Markup %
         //    7: Custom 2
         //    8: Customized Price
         //    9: Remove
         if (ConfigurationManager.AppSettings["ParentProductCustomHeader1"] != null)
         {
            gridQuoteItems3.Columns[1].HeaderText = ConfigurationManager.AppSettings["ParentProductCustomHeader1"];
            gridQuoteItems3.Columns[1].Visible = true;
         }
         else
         {
            gridQuoteItems3.Columns[1].Visible = false;
         }

         if (ConfigurationManager.AppSettings["ParentProductCustomHeader2"] != null)
         {
            gridQuoteItems3.Columns[7].HeaderText = ConfigurationManager.AppSettings["ParentProductCustomHeader2"];
            gridQuoteItems3.Columns[7].Visible = true;
         }
         else
         {
            gridQuoteItems3.Columns[7].Visible = false;
         }

         if (ConfigurationManager.AppSettings["ShowMultiplierColumn"] != null)
         {
            bool bVisible = Convert.ToBoolean(ConfigurationManager.AppSettings["ShowMultiplierColumn"]);
            gridQuoteItems3.Columns[4].Visible = bVisible;
         }

         if (ConfigurationManager.AppSettings["ShowQtyColumn"] != null)
         {
            bool bVisible = Convert.ToBoolean(ConfigurationManager.AppSettings["ShowQtyColumn"]);
            gridQuoteItems3.Columns[3].Visible = bVisible;
         }

         if (ConfigurationManager.AppSettings["ShowPercentDiscountColumn"] != null)
         {
            bool bVisible = Convert.ToBoolean(ConfigurationManager.AppSettings["ShowPercentDiscountColumn"]);
            gridQuoteItems3.Columns[5].Visible = bVisible;
         }

         if (ConfigurationManager.AppSettings["ShowPercentMarkupColumn"] != null)
         {
            bool bVisible = Convert.ToBoolean(ConfigurationManager.AppSettings["ShowPercentMarkupColumn"]);
            gridQuoteItems3.Columns[6].Visible = bVisible;
         }

         if (ConfigurationManager.AppSettings["ShowCustomizedPriceColumn"] != null)
         {
            bool bVisible = Convert.ToBoolean(ConfigurationManager.AppSettings["ShowCustomizedPriceColumn"]);
            gridQuoteItems3.Columns[8].Visible = bVisible;
         }

         btnDiscount.Visible = false;
         if (ConfigurationManager.AppSettings["CustomDiscountUrl"] != null)
         {
            if (ConfigurationManager.AppSettings["CustomDiscountUrl"] != "")
            {
               btnDiscount.Visible = true;
            }
         }
      }

      private void AddItem(string strProductID, string strCategoryId)
      {
         Product prod = eng.LoadProduct(new Guid(strProductID), objQuote.PriceLevelId);

         XmlNode nodeProduct = eng.GetProductNode(nodeCategoryList, strCategoryId, prod.ProductNumber);

         if (nodeProduct.Attributes["allowDiscounting"] != null)
         {
            prod.AllowDiscounting = Convert.ToBoolean(nodeProduct.Attributes["allowDiscounting"].Value);
         }

         prod.CategoryId = strCategoryId;
         QuoteDetail objNewItem = eng.AddProduct(objQuote, prod);
         eng.AutoAddChildProducts(objQuote, objNewItem, objOrganization);

         // Reload the line items so that discounts are properly applied
         eng.LoadLineItems(objQuote);

         // Refresh the list of selected line items
         RefreshQuoteItems();
      }

      private void ConfigureItem(string strProductID)
      {
         Response.Redirect("CustomizeItem.aspx?QuoteId=" + m_strQuoteId + "&QuoteDetailId=" + strProductID);
      }

      private void RemoveItem(string strQuoteDetailID)
      {
         if (Trace.IsEnabled)
            Trace.Write("RemoveItem", "QuoteDetailId=" + strQuoteDetailID);

         QuoteDetail objItem = objQuote.FindQuoteDetail(new Guid(strQuoteDetailID));

         eng.RemoveParentItem(objItem);
         RefreshQuoteItems();

         if (Trace.IsEnabled)
            Trace.Write("RemoveItem", "Complete.");
      }

      public void LoadCategoryList()
      {
         nodeCategoryList = eng.LoadProductCategoryList();

         if (nodeCategoryList == null)
         {
            throw new ApplicationException("The <CategoryList> node was not found in the CategoryList.xml file.");
         }
      }

      public void LoadProductCategoryList(Infragistics.WebUI.UltraWebNavigator.UltraWebTree treeControl)
      {
         eng.DebugMessage("CustomizeQuote.LoadProductCategoryList() 1");

         Node nodeRoot = new Node();

         LoadChildItems(nodeRoot, nodeCategoryList);
         treeControl.Nodes.Clear();

         foreach (Node item in nodeRoot.Nodes)
         {
            treeControl.Nodes.Add(item);
         }

         eng.DebugMessage("CustomizeQuote.LoadProductCategoryList() 2");
      }

      public void LoadProductCategoryList2(TreeView treeControl)
      {
         eng.DebugMessage("CustomizeQuote.LoadProductCategoryList() 1");

         TreeNode nodeRoot = new TreeNode();

         LoadChildItems2(nodeRoot, nodeCategoryList);
         treeControl.Nodes.Clear();

         for (int i = 0; i < nodeRoot.ChildNodes.Count; i++)
         {
            TreeNode item = nodeRoot.ChildNodes[i];
            treeControl.Nodes.Add(item);
         }

         /*
         foreach (TreeNode item in nodeRoot.ChildNodes)
         {
             item.clo
             treeControl.Nodes.Add(item);
         } */

         eng.DebugMessage("CustomizeQuote.LoadProductCategoryList() 2");
      }

      private void LoadChildItems2(TreeNode treeParentNode, XmlNode xmlParentNode)
      {
         string strNodeName = "";

         try
         {
            foreach (XmlNode nodeChild in xmlParentNode.ChildNodes)
            {
               if (nodeChild.Name == "Category")
               {
                  strNodeName = nodeChild.Attributes["name"].Value;
                  TreeNode nodeItem = new TreeNode(strNodeName, null);

                  XmlAttribute attrib = nodeChild.Attributes["categoryId"];

                  // categoryId attribute is optional
                  if (attrib == null)
                     nodeItem.Value = "";
                  else
                     nodeItem.Value = attrib.Value;

                  LoadChildItems2(nodeItem, nodeChild);
                  treeParentNode.ChildNodes.Add(nodeItem);
               }
            }
         }
         catch (Exception ex)
         {
            string strMessage = "There was an error processing the category tree item named: " + strNodeName;
            throw new ApplicationException(strMessage, ex);
         }
      }

      private void LoadChildItems(Node treeParentNode, XmlNode xmlParentNode)
      {
         string strNodeName = "";

         try
         {
            foreach (XmlNode nodeChild in xmlParentNode.ChildNodes)
            {
               if (nodeChild.Name == "Category")
               {
                  strNodeName = nodeChild.Attributes["name"].Value;
                  Node nodeItem = new Node(strNodeName, null);

                  XmlAttribute attrib = nodeChild.Attributes["categoryId"];

                  // categoryId attribute is optional
                  if (attrib == null)
                     nodeItem.Tag = "";
                  else
                     nodeItem.Tag = attrib.Value;

                  LoadChildItems(nodeItem, nodeChild);
                  treeParentNode.Nodes.Add(nodeItem);
               }
            }
         }
         catch (Exception ex)
         {
            string strMessage = "There was an error processing the category tree item named: " + strNodeName;
            throw new ApplicationException(strMessage, ex);
         }
      }

      private void SelectCategory(string strTargetCategoryId)
      {
         if (ctlTree.Nodes.Count > 0)
         {
            ctlTree.SelectedNode = ctlTree.Nodes[0];

            if (strTargetCategoryId != "")
            {
               Node objCategoryNode = ctlTree.Find(strTargetCategoryId);

               if (objCategoryNode != null)
               {
                  ctlTree.SelectedNode = objCategoryNode;
               }
            }
         }
      }

      private void ctlTree_NodeClicked(object sender, Infragistics.WebUI.UltraWebNavigator.WebTreeNodeEventArgs e)
      {
         if (this.Trace.IsEnabled)
            this.Trace.Write("Tree node clicked. Item = " + e.Node.Tag.ToString());

         RefreshAvailableProducts();
      }

      private void RefreshAvailableProducts()
      {
         string strCategoryId = ctlTree.SelectedNode.Tag.ToString();

         lblAvailableItemsInCategory.Text = m_mgrResource.GetString("lblAvailableItemsInCategory");
         lblAvailableItemsInCategory.Text += " " + ctlTree.SelectedNode.Text;

         if (strCategoryId == "")
         {
            throw new ProductConfigException("There is an error in the CategoryList.xml file. A categoryId value was not found for this category:" + ctlTree.SelectedNode.Text);
         }
         else
         {
            ArrayList objProductList = eng.LoadCategoryItems(strCategoryId, objQuote.PriceLevelId);

            if (objProductList.Count == 0)
            {
               // Prevent the gridview control from being hidden
               objProductList.Add(new Product());
               gridAvailableProducts3.DataSource = objProductList;
               gridAvailableProducts3.DataBind();
               gridAvailableProducts3.Rows[0].Visible = false;
            }
            else
            {
               gridAvailableProducts3.DataSource = objProductList;
               gridAvailableProducts3.DataBind();
            }
         }
      }

      private void RefreshQuoteItems()
      {
         gridQuoteItems3.DataSource = objQuote.GetConfigurableItems();
         gridQuoteItems3.DataBind();
      }

      protected string CalculateItemPrice(object val)
      {
         QuoteDetail objItem = (QuoteDetail)val;
         decimal nPrice = objItem.CalculatePrice();

         string strResult = Product.FormatCurrency(nPrice, nCurrencyFormatCode, strCurrencySymbol);

         return strResult;
      }

      private void gridAvailableProducts_ItemCreated(object sender, System.Web.UI.WebControls.DataGridItemEventArgs e)
      {
         ApplyGridHeaderStyle(e);
      }

      private void ApplyGridHeaderStyle(System.Web.UI.WebControls.DataGridItemEventArgs e)
      {
         if (e.Item.ItemType == ListItemType.Header)
         {
            foreach (TableCell cell in e.Item.Cells)
            {
               cell.BorderWidth = Unit.Pixel(1);
               cell.BorderStyle = BorderStyle.Solid;
               cell.BorderColor = Color.Gray;
               cell.Style.Add("border-left-color", "White");
               cell.Style.Add("border-left-width", "2px");
               cell.Style.Add("border-left-style", "Outset");
               cell.Style.Add("border-top-color", "LightGrey");
               cell.Style.Add("border-bottom-color", "DarkGray");
               cell.Style.Add("border-bottom-width", "2px");
               cell.Style.Add("border-top-style", "Outset");
               cell.Style.Add("border-bottom-style", "Solid");
               cell.Style.Add("padding-left", "3px");
            }
         }
      }


      /*
      private void gridQuoteItems2_InitializeRow(object sender, Infragistics.WebUI.UltraWebGrid.RowEventArgs e)
      {
          QuoteDetail objLineItem = (QuoteDetail)e.Data;
          string strRuleFileName = eng.GetRuleFileName(objLineItem);
          string strConfigureUrl = "javascript:customizeItem(\"CustomizeItem.aspx?QuoteId=" + m_strQuoteId + "&QuoteDetailId=" + objLineItem.QuoteDetailId + "\")";
          string strRemoveUrl = "javascript:removeItem(\"" + objLineItem.QuoteDetailId + "\");";
          string strRemoveCommand = m_mgrResource.GetString("cmdRemove");

          if (objQuote.IsReadOnly)
          {
              strRemoveUrl = "javascript:alert('This quote is read-only.')";
          }

          e.Row.Tag = objLineItem.QuoteDetailId.ToString();

          e.Row.Cells[0].Text = objLineItem.Name;
          e.Row.Cells[0].Title = objLineItem.Name;

          if (strRuleFileName != "")
          {
              e.Row.Cells[0].TargetURL = strConfigureUrl;
              e.Row.Cells[0].Style.ForeColor = objCustomizeLinkColor;
          }

          e.Row.Cells[2].Text = Product.FormatCurrency(objLineItem.PricePerUnit, nCurrencyFormatCode, strCurrencySymbol);

          decimal nMultiplier = objLineItem.ConvertFixedDiscountToPercentage();
          e.Row.Cells[4].Text = nMultiplier.ToString();

          e.Row.Cells[8].Text = CalculateItemPrice(objLineItem);

          e.Row.Cells[9].Text = strRemoveCommand;
          e.Row.Cells[9].TargetURL = strRemoveUrl;
      }
       * */
      /*

      private void gridQuoteItems2_UpdateCell(object sender, Infragistics.WebUI.UltraWebGrid.CellEventArgs e)
      {
          string strQuoteDetailId = e.Cell.Row.Tag.ToString();

          // Reload the line items so that discounts are properly applied
          eng.LoadLineItems(objQuote);
          QuoteDetail objLineItem = objQuote.FindQuoteDetail(new Guid(strQuoteDetailId));

          try
          {
              switch (e.Cell.Column.Index)
              {
                  case 3:
                      // Quantity
                      int nNewQty = Convert.ToInt32(e.Cell.Text);

                      eng.ChangeParentItemQty(objQuote, strQuoteDetailId, nNewQty);

                      decimal nPercentageDiscount = Convert.ToDecimal(e.Cell.Row.Cells[4].Text);
                      objLineItem.ApplyPercentageMultiplier(nPercentageDiscount);

                      // Refresh the list of selected line items
                      RefreshQuoteItems();
                      break;

                  case 4:
                      // Multiplier
                      decimal nNewMultiplier = Convert.ToDecimal(e.Cell.Text);

                      objLineItem.ApplyPercentageMultiplier(nNewMultiplier);

                      eng.UpdateQuoteDetail(objLineItem);

                      // Refresh the list of selected line items
                      RefreshQuoteItems();
                      break;

                  case 5:
                      // Percent Discount
                      decimal nNewDiscount = Convert.ToDecimal(e.Cell.Text);

                      objLineItem.PercentDiscount = nNewDiscount;
                      objLineItem.RefreshMultiplier();

                      eng.UpdateQuoteDetail(objLineItem);
                      eng.UpdateQuote(objQuote);

                      // Refresh the list of selected line items
                      RefreshQuoteItems();
                      break;

                  case 6:
                      // Percent Markup
                      decimal nNewMarkup = Convert.ToDecimal(e.Cell.Text);

                      objLineItem.PercentMarkup = nNewMarkup;
                      objLineItem.RefreshMultiplier();

                      eng.UpdateQuoteDetail(objLineItem);
                      eng.UpdateQuote(objQuote);

                      // Refresh the list of selected line items
                      RefreshQuoteItems();
                      break;

              }
          }
          catch (Exception ex)
          {
              Trace.Write("gridQuoteItems2_UpdateCell", "Error" + ex.Message);
          }
      }
      */

      protected void btnAddItem_Click(object sender, System.EventArgs e)
      {
         string strProductId = txtProductId.Text;
         string strCategoryId = ctlTree.SelectedNode.Tag.ToString();

         AddItem(strProductId, strCategoryId);
      }

      protected void btnRemoveItem_Click(object sender, System.EventArgs e)
      {
         string strQuoteDetailId = txtProductId.Text;
         RemoveItem(strQuoteDetailId);
      }

      private void btnDiscount_Click(object sender, System.Web.UI.ImageClickEventArgs e)
      {
         string strTargetUrl = ConfigurationManager.AppSettings["CustomDiscountUrl"];
         Response.Redirect(strTargetUrl + "?QuoteId=" + m_strQuoteId);
      }

      protected void gridAvailableProducts3_RowDataBound(object sender, GridViewRowEventArgs e)
      {
         if (e.Row.RowType == DataControlRowType.DataRow)
         {
            Product objProduct = (Product)e.Row.DataItem;
            string strAddUrl = "javascript:addItem(\"" + objProduct.ProductId + "\");";
            string strAddCommand = m_mgrResource.GetString("cmdAdd");

            if (objQuote.IsReadOnly)
            {
               strAddUrl = "javascript:alert('This quote is read-only.')";
            }

            HyperLink lnkAdd = (HyperLink)e.Row.Cells[0].FindControl("lnkAdd");
            lnkAdd.Text = strAddCommand;
            lnkAdd.NavigateUrl = strAddUrl;

            e.Row.Cells[3].Text = Product.FormatCurrency(objProduct.StandardCost, nCurrencyFormatCode, strCurrencySymbol);
            e.Row.Cells[4].Text = Product.FormatCurrency(objProduct.ListPrice, nCurrencyFormatCode, strCurrencySymbol);
            e.Row.Cells[5].Text = Product.FormatCurrency(objProduct.Price, nCurrencyFormatCode, strCurrencySymbol);
         }
      }


      // Quote Item columns are:
      //    0: Name
      //    1: Custom 1
      //    2: Base Price
      //    3: Qty
      //    4: Multiplier
      //    5: Discount %
      //    6: Markup %
      //    7: Custom 2
      //    8: Customized Price
      //    9: Remove
      protected void gridQuoteItems3_RowDataBound(object sender, GridViewRowEventArgs e)
      {
         if (e.Row.RowType == DataControlRowType.DataRow)
         {
            QuoteDetail objLineItem = (QuoteDetail)e.Row.DataItem;
            string strRuleFileName = eng.GetRuleFileName(objLineItem);
            string strConfigureUrl = "javascript:customizeItem(\"CustomizeItem.aspx?QuoteId=" + m_strQuoteId + "&QuoteDetailId=" + objLineItem.QuoteDetailId + "\")";
            string strRemoveUrl = "javascript:removeItem(\"" + objLineItem.QuoteDetailId + "\");";
            string strRemoveCommand = m_mgrResource.GetString("cmdRemove");

            if (objQuote.IsReadOnly)
            {
               strRemoveUrl = "javascript:alert('This quote is read-only.')";
            }

            // Update the customize link
            HyperLink lnkCustomize = (HyperLink)e.Row.Cells[0].FindControl("lnkCustomize");
            lnkCustomize.Text = objLineItem.Name;

            if (strRuleFileName != "")
            {
               lnkCustomize.NavigateUrl = strConfigureUrl;
               lnkCustomize.ForeColor = objCustomizeLinkColor;
            }

            e.Row.Cells[2].Text = Product.FormatCurrency(objLineItem.PricePerUnit, nCurrencyFormatCode, strCurrencySymbol);

            // Setup Qty column for editing
            TextBox txtQty = (TextBox)e.Row.Cells[3].FindControl("txtQty");
            Label lblQty = (Label)e.Row.Cells[3].FindControl("lblQty");

            if (objQuote.IsReadOnly)
            {
               txtQty.Visible = false; // No editing allowed
            }
            else
            {
               e.Row.Cells[3].Attributes.Add("onclick", "onQtyClick(\"" + txtQty.UniqueID + "\", \"" + lblQty.ClientID + "\", \"" + objLineItem.QuoteDetailId + "\")");
               e.Row.Cells[3].Style.Add("cursor", "pointer");
            }

            // Setup Multiplier/Discount column for editing
            TextBox txtMultiplier = (TextBox)e.Row.Cells[4].FindControl("txtMultiplier");
            Label lblMultiplier = (Label)e.Row.Cells[4].FindControl("lblMultiplier");
            decimal nMultiplier = objLineItem.ConvertFixedDiscountToPercentage();
            lblMultiplier.Text = nMultiplier.ToString();
            txtMultiplier.Text = nMultiplier.ToString();

            if (objQuote.IsReadOnly)
            {
               txtMultiplier.Visible = false; // No editing allowed
            }
            else
            {
               e.Row.Cells[4].Attributes.Add("onclick", "onMultiplierClick(\"" + txtMultiplier.UniqueID + "\", \"" + lblMultiplier.ClientID + "\", \"" + objLineItem.QuoteDetailId + "\")");
               e.Row.Cells[4].Style.Add("cursor", "pointer");
            }


            // Setup Percent Discount column for editing
            TextBox txtPercentDiscount = (TextBox)e.Row.Cells[5].FindControl("txtPercentDiscount");
            Label lblPercentDiscount = (Label)e.Row.Cells[5].FindControl("lblPercentDiscount");
            lblPercentDiscount.Text = objLineItem.PercentDiscount.ToString();
            txtPercentDiscount.Text = objLineItem.PercentDiscount.ToString();

            if (objQuote.IsReadOnly)
            {
               txtPercentDiscount.Visible = false; // No editing allowed
            }
            else
            {
               e.Row.Cells[5].Attributes.Add("onclick", "onPercentDiscountClick(\"" + txtPercentDiscount.UniqueID + "\", \"" + lblPercentDiscount.ClientID + "\", \"" + objLineItem.QuoteDetailId + "\")");
               e.Row.Cells[5].Style.Add("cursor", "pointer");
            }

            // Setup Percent Markup column for editing
            TextBox txtPercentMarkup = (TextBox)e.Row.Cells[5].FindControl("txtPercentMarkup");
            Label lblPercentMarkup = (Label)e.Row.Cells[5].FindControl("lblPercentMarkup");
            lblPercentMarkup.Text = objLineItem.PercentMarkup.ToString();
            txtPercentMarkup.Text = objLineItem.PercentMarkup.ToString();

            if (objQuote.IsReadOnly)
            {
               txtPercentMarkup.Visible = false; // No editing allowed
            }
            else
            {
               e.Row.Cells[6].Attributes.Add("onclick", "onPercentMarkupClick(\"" + txtPercentMarkup.UniqueID + "\", \"" + lblPercentMarkup.ClientID + "\", \"" + objLineItem.QuoteDetailId + "\")");
               e.Row.Cells[6].Style.Add("cursor", "pointer");
            }

            e.Row.Cells[8].Text = CalculateItemPrice(objLineItem);

            HyperLink lnkRemove = (HyperLink)e.Row.Cells[9].FindControl("lnkRemove");
            lnkRemove.Text = strRemoveCommand;
            lnkRemove.NavigateUrl = strRemoveUrl;
         }
      }

      protected void btnEditQty_Click(object sender, EventArgs e)
      {
         string strQuoteDetailId = txtProductId.Text;

         // Reload the line items so that discounts are properly applied
         eng.LoadLineItems(objQuote);
         QuoteDetail objLineItem = objQuote.FindQuoteDetail(new Guid(strQuoteDetailId));

         int nNewQty = Convert.ToInt32(txtValue.Text);

         eng.ChangeParentItemQty(objQuote, strQuoteDetailId, nNewQty);

         decimal nPercentageDiscount = objLineItem.PercentDiscount;
         objLineItem.ApplyPercentageMultiplier(nPercentageDiscount);

         // Refresh the list of selected line items
         RefreshQuoteItems();
      }

      protected void btnEditMultiplier_Click(object sender, EventArgs e)
      {
         string strQuoteDetailId = txtProductId.Text;

         // Reload the line items so that discounts are properly applied
         eng.LoadLineItems(objQuote);
         QuoteDetail objLineItem = objQuote.FindQuoteDetail(new Guid(strQuoteDetailId));

         decimal nNewMultiplier = Convert.ToDecimal(txtValue.Text);

         objLineItem.ApplyPercentageMultiplier(nNewMultiplier);

         eng.UpdateQuoteDetail(objLineItem);

         // Refresh the list of selected line items
         RefreshQuoteItems();
      }

      protected void btnEditPercentDiscount_Click(object sender, EventArgs e)
      {
         string strQuoteDetailId = txtProductId.Text;
         // Reload the line items so that discounts are properly applied
         eng.LoadLineItems(objQuote);
         QuoteDetail objLineItem = objQuote.FindQuoteDetail(new Guid(strQuoteDetailId));

         decimal nNewDiscount = Convert.ToDecimal(txtValue.Text);

         objLineItem.PercentDiscount = nNewDiscount;
         objLineItem.RefreshMultiplier();

         eng.UpdateQuoteDetail(objLineItem);
         eng.UpdateQuote(objQuote);

         // Refresh the list of selected line items
         RefreshQuoteItems();
      }

      protected void btnEditPercentMarkup_Click(object sender, EventArgs e)
      {
         string strQuoteDetailId = txtProductId.Text;
         // Reload the line items so that discounts are properly applied
         eng.LoadLineItems(objQuote);
         QuoteDetail objLineItem = objQuote.FindQuoteDetail(new Guid(strQuoteDetailId));

         decimal nNewMarkup = Convert.ToDecimal(txtValue.Text);

         objLineItem.PercentMarkup = nNewMarkup;
         objLineItem.RefreshMultiplier();

         eng.UpdateQuoteDetail(objLineItem);
         eng.UpdateQuote(objQuote);

         // Refresh the list of selected line items
         RefreshQuoteItems();
      }


   }  // end class
}
